
package com.oswego.dawcs;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class ChannelController extends LinearLayout {
	private final int PAN_MIDI_CODE = 0xa;
	private final int GAIN_MIDI_CODE = 0x7;
	private final int EQH_MIDI_CODE = 0x1a;
	private final int EQM_MIDI_CODE = 0x1b;
	private final int EQL_MIDI_CODE = 0x1c;

	private ImageButton close;
	private Dial pan;
	private Dial eq_high;
	private Dial eq_mid;
	private Dial eq_low;
	private TextView panLvl;
	private TextView gainLvl;
	private VerticalSlider gain;
	private Spinner chanNumSpinner;
	
	private final boolean show_eq;
	private final boolean show_pan;
	private final boolean show_gain;
	
	private int currentProgress;
	
	private Channel chan;
	private Channels chans = DAWCS.chans;
    private int chanNum;
	
	private ArrayAdapter<Integer> dataAdapter;
	private HashMap<Integer, Group> group = DAWCS.groupsMap;
	private List<Integer> availChans;
	private GroupListener gl;
	
	private RadioGroup radioGroup;
	private RadioButton groupOne;
	private RadioButton groupTwo;
	private RadioButton groupThree;
	private RadioButton groupFour;
	
	public int masterProg;
	public Channel masterChan;

    private boolean click;
	
	public ChannelController(Context context, boolean eqb, boolean panb, boolean gainb, Channel chanIn, boolean toClick) {
		super(context);
		this.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
//		this.setBackgroundColor(getResources().getColor(R.color.Black));

        this.click = toClick;

        System.out.println("I am a new channel, my # is: " + chanIn.getChanID());

		this.show_eq = eqb;
		this.show_gain = gainb;
		this.show_pan = panb;
		
		this.chan = chanIn;
        this.chanNum = chan.getChanID();
		
		LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		inflater.inflate(R.layout.channel_layout, this);

		close = (ImageButton)findViewById(R.id.close);
		
		availChans = new ArrayList<Integer>();
	    availChans.add(0, chan.getChanID());

        if (!DAWCS.getAvailableChannelNumbers().isEmpty()) {
        	for (Integer i : DAWCS.getAvailableChannelNumbers()) {
        		availChans.add(i);
        	}
        }
            
        chanNumSpinner = (Spinner) findViewById(R.id.chan_num);
        
        dataAdapter = new ArrayAdapter<Integer>(this.getContext(), R.layout.spinner_item, availChans);
        dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        chanNumSpinner.setAdapter(dataAdapter);
        
        chanNumSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
        	public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
            	int newChan = Integer.parseInt(parent.getItemAtPosition(pos).toString());

            	if (id > 0) {
            		DAWCS.availableChans.add(chan);


                    DAWCS.removeAvailableChan(newChan);
                    DAWCS.addAvailableChan(chanNum);
                    chanNum = newChan;

                    availChans.remove(0);
                    updateAvailableChannels(availChans);
            	}

                if (chan.getChanID()!=newChan) {
                    clearRadio();
//                    resetController();
                }
                chan = chans.getChan(newChan);
                DAWCS.availableChans.remove(chan);


            }
            public void onNothingSelected(AdapterView<?> parent) {}
        });
        
		if (show_eq) {
			eq_high = (Dial) findViewById(R.id.eq_high);
            eq_high.setClick(click);
			eq_high.setImageResource(R.drawable.bnb_knob);
			eq_high.setDialListener(new Dial.DialListener() {
				@Override
				public void onDialChanged(float delta, float val) {
					NetHandler.getInstance().receivePacketFromChannel(
							new MIDIPacket(chan.getChanID(), EQH_MIDI_CODE, eq_high.getDialVal()));
				}	
			});
			eq_mid = (Dial) findViewById(R.id.eq_mid);
            eq_mid.setClick(click);
			eq_mid.setImageResource(R.drawable.bnb_knob);
			eq_mid.setDialListener(new Dial.DialListener() {
				@Override
				public void onDialChanged(float delta, float val) {
					NetHandler.getInstance().receivePacketFromChannel(
							new MIDIPacket(chan.getChanID(), EQM_MIDI_CODE, eq_mid.getDialVal()));
				}	
			});
			eq_low = (Dial) findViewById(R.id.eq_low);
            eq_low.setClick(click);
			eq_low.setImageResource(R.drawable.bnb_knob);
			eq_low.setDialListener(new Dial.DialListener() {
				@Override
				public void onDialChanged(float delta, float val) {
					NetHandler.getInstance().receivePacketFromChannel(
							new MIDIPacket(chan.getChanID(), EQL_MIDI_CODE, eq_low.getDialVal()));
				}	
			});
		}
		if (show_pan) {
			pan = (Dial) findViewById(R.id.pan);
            pan.setClick(click);
			pan.setImageResource(R.drawable.bnb_knob);
			panLvl = (TextView) findViewById(R.id.pan_lvl);
			pan.setDialListener(new Dial.DialListener() {
				@Override
				public void onDialChanged(float delta, float val) {
					if(val<=150){
						//rotating left
						double x = Math.ceil((((val - 150)/150)*100));
						double y = Math.abs(x);
						if(y == 0.0d){
							panLvl.setText("0.0");
						} else{
							panLvl.setText("L " + Math.abs(x));
						}
					}else{
						//rotating right
						double x = Math.floor((((val - 150)/150)*100));
						panLvl.setText("R " + Math.abs(x));
					}
					
					NetHandler.getInstance().receivePacketFromChannel(
							new MIDIPacket(chanNum, PAN_MIDI_CODE, pan.getDialVal()));
				}	
			});
		}
		
		if (show_gain) {
			gain = (VerticalSlider) findViewById(R.id.gain);
			gain.setMax(Byte.MAX_VALUE);
			gain.setThumb(getResources().getDrawable(R.drawable.bnb_thumb));
			gainLvl = (TextView) findViewById(R.id.gain_lvl);
            adjustGain();
		}
		
		radioGroup = (RadioGroup) findViewById(R.id.radioGroups);
		groupOne = (RadioButton) findViewById(R.id.group1);
		groupTwo = (RadioButton) findViewById(R.id.group2);
		groupThree = (RadioButton) findViewById(R.id.group3);
		groupFour = (RadioButton) findViewById(R.id.group4);
		
		groupOne.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if(groupOne.isSelected()) {
                    groupOne.setSelected(false);
					radioGroup.clearCheck();
//					System.out.println(chan.getChanID() + " removed from group " + chan.getGroup());
					group.get(chan.getGroup()).remove(chan);
					chan.setGrouped(false);
                    if (chan == masterChan && !group.get(1).isEmpty()) {
                        setMaster(1);
                    }
                }
                else{
                	makeGroup(1);
                	groupOne.setSelected(true);
                	groupTwo.setSelected(false);
                	groupThree.setSelected(false);
                	groupFour.setSelected(false);
                	radioGroup.check(R.id.group1);
//                	System.out.println("Checking group1");
                }
			}
		});
		groupTwo.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if(groupTwo.isSelected()) {
                    groupTwo.setSelected(false);
					radioGroup.clearCheck();
//					System.out.println(chan.getChanID() + " removed from group " + chan.getGroup());
					group.get(chan.getGroup()).remove(chan);
					chan.setGrouped(false);
                    if (chan == masterChan && !group.get(2).isEmpty()) {
                        setMaster(2);
                    }
                }
                else{
                	makeGroup(2);
                	groupOne.setSelected(false);
                	groupTwo.setSelected(true);
                	groupThree.setSelected(false);
                	groupFour.setSelected(false);
                	radioGroup.check(R.id.group2);
//                	System.out.println("Checking group2");
                }
			}
		});
		groupThree.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if(groupThree.isSelected()) {
					groupThree.setSelected(false);
					radioGroup.clearCheck();
//					System.out.println(chan.getChanID() + " removed from group " + chan.getGroup());
					group.get(chan.getGroup()).remove(chan);
					chan.setGrouped(false);
                    if (chan == masterChan && !group.get(3).isEmpty()) {
                        setMaster(3);
                    }
                }
                else{
                	makeGroup(3);
                	groupTwo.setSelected(false);
                	groupOne.setSelected(false);
                	groupThree.setSelected(true);
                	groupFour.setSelected(false);
                	radioGroup.check(R.id.group3);
//                	System.out.println("Checking group3");
                }
			}
		});
		groupFour.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if(groupFour.isSelected()) {
					groupFour.setSelected(false);
					radioGroup.clearCheck();
//					System.out.println(chan.getChanID() + " removed from group " + chan.getGroup());
					group.get(chan.getGroup()).remove(chan);
					chan.setGrouped(false);
                    if (chan == masterChan && !group.get(4).isEmpty()) {
                        setMaster(4);
                    }
                }
                else{
                	makeGroup(4);
                	groupTwo.setSelected(false);
                	groupOne.setSelected(false);
                	groupThree.setSelected(false);
                	groupFour.setSelected(true);
                	radioGroup.check(R.id.group4);
//                	System.out.println("Checking group4");
                }
			}
		});
	}

    public void setClick(boolean b){
        eq_low.setClick(b);
        eq_mid.setClick(b);
        eq_high.setClick(b);
        pan.setClick(b);
    }

    private void adjustGain() {
        if (chan.isGrouped()) {
            setMaster(chan.getGroup());

            gain.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    if (!chan.isGrouped()) {
                        adjustGain();
                    } else {
                        if (gain.focused()) {
                            getGainLvl().setText(String.format("%.1f", ((getGain().getProgress() / new Float(getGain().getMax())) * 100)));
                            double fade = (double) (getGain().getProgress() / new Float(getGain().getMax()));
                            getChannel().setFade(fade);

                            NetHandler.getInstance().receivePacketFromChannel(
                                    new MIDIPacket(chan.getChanID(), GAIN_MIDI_CODE, gain.getProgress()));

                            for (ChannelController cc : group.get(chan.getGroup()).keys()) {
                                if (cc.getChannelNum() == getChannelNum()) {
                                    continue;
                                } else {
                                    cc.getGain().setProgress((gain.getProgress() - currentProgress) + cc.getSliderProg());
                                    cc.getGain().updateThumb();
                                    cc.getGainLvl().setText(String.format("%.1f", ((cc.getGain().getProgress() / new Float(cc.getGain().getMax())) * 100)));
                                    cc.getChannel().setFade((double) (cc.getGain().getProgress() / new Float(cc.getGain().getMax())));

                                    NetHandler.getInstance().receivePacketFromChannel(
                                            new MIDIPacket(cc.getChannelNum(), GAIN_MIDI_CODE, cc.getGain().getProgress()));
                                }
                            }
                        }
                    }
                }
                @Override public void onStartTrackingTouch(SeekBar seekBar) {}
                @Override public void onStopTrackingTouch(SeekBar seekBar) {}
            });
        } else {
            gain.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    if (chan.isGrouped()) {
                        adjustGain();
                    } else {

                        gainLvl.setText(String.format("%.1f", ((gain.getProgress() / new Float(gain.getMax())) * 100)));
                        double fade = (double) (gain.getProgress() / new Float(gain.getMax()));
                        currentProgress = gain.getProgress();
                        chan.setFade(fade);
                        NetHandler.getInstance().receivePacketFromChannel(
                                new MIDIPacket(chan.getChanID(), GAIN_MIDI_CODE, gain.getProgress()));

                    }
                }
                @Override public void onStartTrackingTouch(SeekBar arg0) {}
                @Override public void onStopTrackingTouch(SeekBar arg0) {}
            });
        }
    }

    private void setMaster(int groupID) {
        masterChan = group.get(groupID).setMasterFader();
    }

    public int getSliderProg() {
        return currentProgress;
    }
	
	protected void makeGroup(int i) {
		if (chan.isGrouped()) {
			group.get(chan.getGroup()).remove(chan);
			chan.setGrouped(false);
		}
		
		group.get(i).add(this, chan);
		chan.setGrouped(true);
		chan.setGroup(i);
		
//		System.out.println(chan.getChanID() + " added to group " + chan.getGroup() + " " + chan.isGrouped());
	}

	public void addCloseListener(OnClickListener ocl){
		close.setOnClickListener(ocl);
	}

    public Channel getChannel() {
        return chan;
    }
	
	public int getChannelNum(){
		return chan.getChanID();
	}
	
	public VerticalSlider getGain() {
		return gain;
	}
	
	public TextView getGainLvl() {
		return gainLvl;
	}
	
	public void setPanImgById(int id){
		pan.setImageResource(id);
	}
	
	public void setEQImgsById(int id){
		eq_high.setImageResource(id);
		eq_mid.setImageResource(id);
		eq_low.setImageResource(id);
	}
	
	public void setSliderImgsByIds(int thumbId, int progressId){
		gain.setThumb(getResources().getDrawable(thumbId));
        gain.setProgressDrawable(getResources().getDrawable(progressId));
        gain.updateThumb(); //<-- this is needed for the seekbar to update!!! DO NOT REMOVE
	}

    public void setCloseButtonById(int id){
        close.setImageDrawable(getResources().getDrawable(id));
    }

	public void updateAvailableChannels(List<Integer> channels){
        int gainVal = gain.getProgress();
        ArrayList<Integer> chanList = new ArrayList<Integer>(channels);
        chanList.add(0, chanNum);

		this.availChans = chanList;
        dataAdapter = new ArrayAdapter<Integer>(this.getContext(), R.layout.spinner_item, availChans);
        dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        chanNumSpinner.setAdapter(dataAdapter);
        gain.setProgress(gainVal);
		System.out.println("Updating available channels in channel# " + chanNum);
	}

    private void clearRadio() {
        if(groupOne.isSelected()) {
            groupOne.setSelected(false);
            radioGroup.clearCheck();
            group.get(chan.getGroup()).remove(chan);
            chan.setGrouped(false);

            if (chan == masterChan && !group.get(1).isEmpty()) {
                setMaster(1);
            }
        } else if(groupTwo.isSelected()) {
            groupTwo.setSelected(false);
            radioGroup.clearCheck();
            group.get(chan.getGroup()).remove(chan);
            chan.setGrouped(false);

            if (chan == masterChan && !group.get(2).isEmpty()) {
                setMaster(2);
            }
        } else if(groupThree.isSelected()) {
            groupThree.setSelected(false);
            radioGroup.clearCheck();
            group.get(chan.getGroup()).remove(chan);
            chan.setGrouped(false);

            if (chan == masterChan && !group.get(3).isEmpty()) {
                setMaster(3);
            }
        } else if(groupFour.isSelected()) {
            groupFour.setSelected(false);
            radioGroup.clearCheck();
            group.get(chan.getGroup()).remove(chan);
            chan.setGrouped(false);

            if (chan == masterChan && !group.get(4).isEmpty()) {
                setMaster(4);
            }
        }
    }

    private void resetController() {
        gain.setProgress(0);
    }
}

